home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-12-10 | 101.1 KB | 2,715 lines |
-
- Topics covered in this tutorial:
-
- * A further introduction to elementary HeliOS programming
- * HeliOS program structure and source code layout
- * Colon Definitions
- * HeliOS "WORDS" and the dictionary
- * The Dictionary memory area
- * A litle more about the terms "Compiling" and "Interpreting"
- * Computer Memory and more about the HeliOS Stack
- * The HeliOS stack display
- * Passing parameters between HeliOS Words and using Stack Diagrams
- * Using 8-bit, 16-Bit and 32-Bit numbers
- * Specifying number sizes
- * Converting between differently sized numbers on the stack
- * Using 16-Bit and 32-Bit memory addressing modes
- * The HeliOS Dictionary is a 16-bit addressed, 16-bit data structure
- * A repeated IMPORTANT warning
- * Converting between 16-bit and 32-bit addresses
- * How HeliOS specifies 16-bit and 32-bit addressing and numbers.
- * Using Variables
- * Using "Text Strings" in HeliOS programs
- * A very simple and useful HeliOS string handling word - "LIT$".
- * General INPUT and OUTPUT using HeliOS
- * Sending text output to the user via the screen display
- * A simple tutorial programming exercise
- * Entering and compiling our new program
- * Using Amiga Libraries from within HeliOS
- * Closing a library
- * Making a library call
- * Making a call to external assembler-generated code
- * General procedures for Starting and Closing programs
- * A typical "universal" start up program
- * A few simple hints on debugging
- * Additional reading?
-
- -------------------------------------------------------
- A further introduction to elementary HeliOS programming
- -------------------------------------------------------
-
- This tutorial can be regarded as a second journey over already slightly
- familiar ground, pointing out new perspectives and landmarks.
-
- In some ways this second tutorial is simpler than the first, so if you did
- not fully grasp the previous material this new presentation may help fill
- in some of the gaps.
-
- There are also some new ideas presented here, building on previous concepts
- and leading to a short program which can be used as a framework for all your
- early HeliOS programs.
-
- HeliOS is a Forth-like language, especially in its simpler aspects, and the
- more sophisticated features of HeliOS build upon a central core of commands
- which are closely related to those defined in the popular and universally
- recognised fig-Forth standard.
-
- This tutorial is concerned mainly with the use of these simple Forth-related
- HeliOS functions, and will give general instruction on Forth programming
- concepts.
-
- You will also find an introduction to several of the most useful of the
- Amiga-specific control functions provided by HeliOS.
-
- This is not a detailed or advanced HeliOS language lesson, and does not deal
- in depth with programming the Amiga operating system and hardware: however,
- it will take you to the point where you can start writing simple and useful
- programs based upon the examples given.
-
- If you follow the introductory instructions and get the small demonstration
- programs working you will, by the end of this tutorial, have a sound basis
- for writing useful programs of your own which include text and graphics.
-
- To help you get started with your own programs we include here a standard
- "start up and close down" mini-program which you can use as a general basis
- for all your early experimental code. This "framework" program will enable
- you to open screens and windows, get user input, print text and display
- graphics: all the elements of simple programming in fact.
-
- The HeliOS disks also include several quite simple source code files which
- will introduce various programming techniques while still being quite easy
- to follow. It is easy to modify these programs with your own ideas and
- variations, and from there you can progress to studying the more complex
- examples provided. If you feel really ambitious you may even like to try
- looking at and modifying the full source code for a complete program such
- as the HeliOS "Defender" game, which is available from Helios Software.
-
- It may be boring in places, but even if you are familiar with Forth-type
- languages please read through all the introductory tutorials BEFORE trying
- to actually change any of the example programs provided. This will help
- prevent initial frustration, because HeliOS is a very unusual language,
- and a certain amount of insight into how HeliOS works is necessary even
- for experienced Forth programmers.
-
-
- -----------------------------------------------
- HeliOS program structure and source code layout
- -----------------------------------------------
-
- The first thing to learn is a sensible way to write and format your "source
- code" in such a way that it is clear to read and easy to comprehend. Much
- of this is a matter of personal style, especially in a language like HeliOS
- which allows very free text formatting within source code.
-
- Computer languages, like people, can only understand text written according
- to certain rules, and even a very free form language like HeliOS requires
- that you obey certain constraints. Fortunately there are very few "rules"
- to learn with HeliOS and there are no artificial constraints such as "line
- numbering", or "strictly typed variables".
-
- Traditional Forth did employ a quite rigid and unusual form of source code
- stored in special "blocks", but HeliOS allows great freedom of text layout
- within the framework of a few simple but necessary rules.
-
- Some computer languages simply allow a whole program to be one single long
- "stream" of code, but this can be highly confusing. The more sophisticated
- languages allow code to be broken down into easy-to-handle sub-sections, or
- "subroutines", which can in turn be logically organised in a clear and
- functionally efficient manner. The latter type of language is generally
- referred to as a "structured language".
-
- HeliOS programs are highly structured, and the language allows the creation
- of subroutines, often called "Words", which are defined using a source code
- construct called the "colon definition". This name is used because each
- new subroutine definition starts with the colon ":" character.
-
- Within the "colon definitions" which define your functional code, there may
- be used all the usual logical constructs such as "IF-ELSE-THEN", "DO-LOOP",
- "BEGIN-UNTIL" etc etc. All these constructs are easy to use and allow you
- to create neat and easy to read logically structured code.
-
- In effect HeliOS programming consists in defining new words which extend the
- language itself, and as such is a very flexible and intuitive process. You
- can lay out programs in a very free way, and you may use any text editor
- which produces standard ASCII files, although it well generally be most
- convenient to use the integrated HeliOS editors because you can compile
- source code directly from there.
-
- The only real rule which you must obey when writing HeliOS source code is
- that, as in normal human language, all words must be separated by at least
- one space.
-
- Other than this "absolute" rule, everything else is a matter of personal
- preference, and it would be inappropriate for us to present too many
- guidelines. However, there are a few general suggestions which might be
- useful.
-
- Generally speaking, it is a good idea to present each small functional
- section of code on its own line, preferably placing the code well to the
- left of the page to allow room for comments on the right.
-
- For example:
-
-
- FORGET **CORE** \ Clear user dictioary
-
- ." Here I am!" \ Introduce myself
-
- WAITSPACE \ Wait for space
-
-
- It is useful to keep comments vertically aligned where possible, and it is
- often worthwhile including stack comments where your code is manipulating
- several parameters on the stack, so that you can see easily what is going
- on with each line of code.
-
- For example:
-
- FORGET **CORE** \ Clear user dictioary
-
- 40 VARIABLE WIDTH \ Width of box to draw on screen
- 40 VARIABLE HEIGHT \ Height of box to draw on screen
- 120 VARIABLE TOPLEFTX \ Top left corner of box X coordinate
- 120 VARIABLE TOPLEFTY \ Top left corner of box Y coordinate
- 6 VARIABLE COLOUR \ Colour of box
-
- : DRAWBOX
-
- SCRCLR \ Clear screen
-
- TOPLEFTX @ TOPLEFTY @ \ Box X and Y offsets - - - X, Y
-
- DDUP \ Duplicate coordinates - - - X, Y, X, Y,
-
- HEIGHT @ + \ Add box height - - - X, Y, X, Y+H
-
- WIDTH @ UNDER+ \ Add box width - - - X, Y, X+W, Y+H
-
- COLOUR @ \ Get box colour - - - X, Y, X+W, Y+H, C
-
- GFXSETAPEN \ Set box colour
-
- GFXRECTFILL \ Draw box
-
- WAITSPACE \ Wait for space
- ;
-
- DRAWBOX \ Test our new word
-
-
- It really is up to you how you lay things out, but do consider the fact
- that your code needs to be readable and easy to debug, which in most cases
- is achieved best by using a regular, carefully formatted, and well spaced
- layout.
-
-
- -----------------
- Colon Definitions
- -----------------
-
- The colon definition allows you to create a "subroutine" consisting of a
- combination of commands and give a name to the resulting functional unit.
-
- The new "definition", or "Word", can then be used by simply entering its
- name in later source code.
-
- You have actually created a new operator which is just as much a part of
- the language as the initial HeliOS Core vocabulary functions.
-
- The start of a new subroutine is designated by a colon, and, after the code
- specifying what the new word does, we end the definition with a semicolon.
-
- Look at the example below:
-
- : NEWWORD |<--------definition-------->| ;
-
- Here you can see the colon and the semicolon with the definition placed in
- between.
-
- Note that immediately following the colon is the word NEWWORD, and, as you
- may have guessed, this is the name of our new subroutine.
-
- Remember that YOU choose the name of the new function: it can be anything
- you like, but always try to use distinctive and descriptive terms to make
- your code more comprehensible to you. If you choose names carefully your
- code can be made almost as readable as English language. On the other hand
- it is very easy to write very incomprehensible code indeed......
-
- A lot of your HeliOS code will consist of the use of the colon definition,
- so you will soon become very familiar with it: there are plenty of examples
- elsewhere in the tutorials.
-
-
- ---------------------------------
- HeliOS "WORDS" and the dictionary
- ---------------------------------
-
- HeliOS subroutines are called "WORDS", the total set of words available is
- called the "VOCABULARY", and the place where all the words are stored in
- the computer's memory is called the "DICTIONARY".
-
- Because HeliOS source code is concerned with very "linguistically" oriented
- activities, and because the definition and use of language is a very vital
- part of HeliOS, the term "WORD" tends to become a rather overworked part of
- HeliOS terminology. This mainly stems from traditional Forth usage.
-
- Historically Forth programmers have always referred to subroutines and
- their definitions as 'WORDS', but this can be confusing because the term
- WORD was used in several different ways in Forth computing parlance -
-
- 1. It defines a quantity of memory - 2 bytes or 16 bits.
-
- 2. It is used to refer to the basic functional units of the Forth
- Language in terms of WHAT THEY DO operationally.
-
- 3. It is used in the English Language sense to refer to the actual NAME
- of the subroutine - the actual letters which you type to define it.
-
- A little care has to be taken, when you are first starting with HeliOS, or
- any other FORTH based language, to understand the context in which the word
- "WORD" is being used!
-
- All the commands and subroutines that HeliOS uses, including both your own
- subroutines and predefined HeliOS word definitions are stored in the HeliOS
- "dictionary".
-
- As each new definition is added, the free space in the HeliOS dictionary is
- reduced. This space has a fixed limit, and you can always see how much room
- is left in the dictionary by looking at the status display at the top left
- of the HeliOS screen. When the dictionary is full you can write no more
- code, but since HeliOS compiled code is VERY compact this would mean that
- you had already written a very large program indeed.
-
- You can list the current words in the Dictionary simply by typing "VLIST" at
- the command line (described later), or using one of the menu options in the
- Interpreter "HeliOS" menu.
-
- It is important to understand how the dictionary works because the general
- compilation method used by HeliOS is quite unlike that of most other Amiga
- languages.
-
-
- Basically this is what happens -
-
- 1. You create a subroutine by typing in one or more lines of source code
- in the form of a named colon definition.
-
- 2. When the source code is interpreted, or compiled, the executable code
- relating to your new word is stored in the dictionary in a form which
- can later be "understood" and acted upon by the computer.
-
- 3. The name you gave the new word is stored SEPARATELY in a special list,
- rather like an index, which allows the word to be found and used later
- merely by entering its name.
-
-
- Important Note:
-
- HeliOS is very different from traditional Forth in the way that it
- stores word names in a separate list. If you are a seasoned Forth
- programmer, or have a book on traditional Forth, you should read and
- remember the following note, as it will beneficially effect your whole
- programming style.
-
- When a HeliOS program is finally run the list of word names is no
- longer needed. This means that when you produce completed stand-
- alone programs the list of names can be omitted. If you think about
- it you will see that this is very useful, because it means that you
- can use long descriptive names for your subroutines without having
- to worry about them cluttering up your program later.
-
- This may seem very obvious, but traditional Forth actually stored the
- word names permanently within the program code and you may find books
- which advise you to use short names for this reason.
-
- Using HeliOS you can relax and use word names as long as you like.
-
- So just try to make your function names useful and descriptive.
-
-
- Every time these three steps are performed the compiled "code" is added to
- the dictionary. If you recompile a subroutine and do not change its name,
- any earlier version(s) remain still stored in the dictionary, and will be
- left in place but superseded by the latest addition.
-
- This means that your latest word definition will always be the one used in
- response to typing the subroutine name, but the "old" definitions will still
- be there lower in the dictionary. If you use the word "FORGET" to clear
- the very latest definition with a certain name from the dictionary, any
- previous definition with that name will now once again be available.
-
- During a typical session you may well work on a program by continually
- recompiling and testing code. If you make no attempt to clear previous
- additions to the dictionary then it will be filled quite quickly with
- multiple definitions. This is not dangerous, but is slightly messy and
- untidy to leave old definitions piling up over a long period: for this
- reason you should learn how to use the "FORGET" command.
-
- The FORGET command allows you to forget any specified definition, and in
- fact you should be careful because it also, at the same time, gets rid of
- any (and every) word compiled SINCE that specified definition.
-
- Thus:
-
- : TEST1 ." Hello" ;
- : TEST2 ." Hello there" ;
- : TEST3 ." Hello there!" ;
- : TEST4 ." BOLDON Hello there!" ;
-
- FORGET TEST3
-
- would leave everything alone up to and including the TEST2 definition, but
- erase everything compiled after this point (TEST3 and TEST4).
-
- The dictionary can be totally cleared back to the fixed CORE dictionary
- (the set of standard words which are available at startup) by using the
- expression:
-
- FORGET **CORE**
-
- Placing this at the start of a program source code file ensures that you
- can keep recompiling the source code without subroutine definitions being
- duplicated and without the dictionary gradually being filled up.
-
- We will from now on call the basic set of HeliOS commands, which is ALWAYS
- available, the CORE dictionary (or vocabulary), and all the subroutines
- defined in your own code as the USER dictionary (or vocabulary).
-
- Here are three command words to list the vocabularies:
-
- CVLIST -> List the CORE vocabulary
- UVLIST -> List the USER vocabulary
- VLIST -> List the CORE vocabulary followed by the USER vocabulary
-
- You can also use the equivalent interpeter menu options.
-
- --------------------------
- The Dictionary memory area
- --------------------------
-
- The HeliOS Dictionary is a 64k reserved memory area with some important
- special properties:
-
- 1. It is where all HeliOS word definitions are stored.
-
- 2. It is where all HeliOS variables are stored.
-
- 3. It is limited in size and cannot be extended.
-
- 4. It can be addressed using 16-bit or 32-bit addressing (See later).
-
- 5. It is located in Amiga FAST memory (where this is available).
-
- The Dictionary memory space is an important and limited commodity, and you
- must be careful not to fill this memory with data which could legitimately
- be stored elsewhere, especially if you are writing large programs.
-
- There is a Dictionary free space readout on the top left of the HeliOS
- status display, and you should keep a careful watch on this at all times.
-
- In general it is possible to make use of the Dictionary memory space for
- all kinds of data storage, and this has the advantage that no specific
- memory allocation need be made, and there is no deallocation to do later.
-
- The Dictionary memory also has the advantage that it can be addressed using
- 16-bit numbers (see later), which reduces program size and simplifies much
- HeliOS stack manipulation.
-
- If you are writing small programs, where Dictionary space is plentiful, it
- is a good idea to use the Dictionary memory for as much of your data storage
- as possible.
-
- However, if your program is quite large, and the code itself requires a lot
- of Dictionary space, you will need to conserve Dictionary memory as much as
- possible. In these circumstances you will probably find it necessary to
- allocate external memory wherever possible for your data storage, leaving
- as much of the Dictionary space free as possible.
-
-
- -----------------------------------------------------------
- A litle more about the terms "Compiling" and "Interpreting"
- -----------------------------------------------------------
-
- This short section of the tutorial is a small "brain teaser" which will
- help prepare the ground for further revelations later. Do not dwell too
- long on this slightly obscure topic, but bear in mind the hints given here
- when reading other sections of the tutorials. Later we will go into this
- subject in greater depth, and everything will become clearer when you have
- learned more about HeliOS programming in general.
-
- First, a little "conventional wisdom".......
-
- The text which contains the program instructions you wish to give to the
- computer is called "source" code, because it is the "starting" point for
- a translation process. This translation produces the actual "executable"
- code which is executed by the computer's CPU (central processing unit).
-
- The process of producing machine-readable CPU executable code from the
- human-readable source code is known as "compiling". Strictly speaking,
- "compiling" is the term used to describe the process whereby the source
- code for a program is converted to executable code in the form of a file
- which can be "run" or "executed" later.
-
- Some computer languages, rather than compiling source code into executable
- code as a whole, translate and execute each bit of source code as they go.
- This process is called "interpreting". The latter languages run programs
- very slowly because of the inefficient on-the-fly interpretation process.
- They do, however, have the advantage that you can "try out" code at once
- to see how it works: an "interpretive" language gives an instant response.
-
- The pure "compiler" languages produce much faster final code, but in turn
- they suffer from a rather serious disadvantage in that the process of
- compilation is quite involved and time consuming. This means that the
- programmer's task of compiling, testing, rewriting, and recompiling can
- be a very slow and non-interactive (often frustrating) occupation.
-
- HeliOS is a "compiler", but it also has an "interpretive mode" as well,
- which is a good thing because it means that you can create fast compiled
- programs AND test them interactively as you go. This feature of HeliOS
- alone is a very good reason for using it as a "learning" language, and
- the efficiency with which it both "interprets" and "compiles" lifts it
- above any other language on the Amiga.
-
- Now for some slightly disturbing "unconventional wisdom".......
-
- Compiling and interpreting are generally (and over-simplistically) regarded
- as two separate "modes of operation", but you should be aware, even at this
- early stage, that the operation of HeliOS is not quite this simple.
-
- Actually, you could say that all compilation is performed by the HeliOS
- interpreter, or that interpretation is performed by the HeliOS compiler!
-
- This is all a matter of perspective, because the terms used are designed
- to be applied to "conventional" standardised computer operations and not
- to the rather subtle and ambivalent way in which HeliOS works.
-
- This can all become a little confusing, but you need to be aware that when
- it is "interpreting" a sequence of instructions HeliOS frequently changes
- from interpretation to compilation depending on what command is being
- processed.
-
- What is worse, in fact, is that WHILE HeliOS is "compiling" any word it is
- always, even AT THE SAME TIME "interpreting" the function which is doing the
- compilation! HeliOS is simultaneously compiling AND interpreting!
-
- This situation relates to the fact that HeliOS is a language which uses its
- own functions to recreate and extend itself.
-
- At any "clock" time, or real-world instant in time, HeliOS can be said to
- be running several functions at once, some of which are "compiling" and
- others of which are "interpreting". Furthermore, these words are not even
- processed "in parallel", but as threaded, or "nested", control structures
- through which the computer CPU makes its way sequentially.
-
- It is important to realise that in HeliOS the processes of compilation and
- interpretation are under direct and immediate programmed control, and that
- as your source code is being processed some functions are interpreted and
- executed at once, while others are being compiled.
-
- Here is an example showing why you need to take care.
-
- The word HEX changes the HeliOS numeric base to hexadecimal, and DECIMAL
- changes the numeric base to decimal, which is the default setting.
-
- Typing
-
- DECIMAL FF .
-
- will generate an error, since "FF" is not a decimal number.
-
- On the other hand, typing
-
- HEX FF .
-
- will not generate an error, since "FF" can now be interpreted as a legal
- hexadecimal number.
-
- Try them at the command line.
-
- Now try this word definition:
-
- : TEST HEX FF . ;
-
- Highlight the above line and use "Amiga-e": you will get an error!
-
- Can you see why?
-
- The reason for the error is that HeliOS actually COMPILES the word HEX,
- and does not execute it, so the numeric base is still DECIMAL when the
- word "FF" is encountered.
-
- HeliOS then tries to INTERPRET the string "FF" (as a number), before it
- compiles it as part of the definition of TEST, and fails because "FF" is
- not a legal decimal numeric value.
-
- What can we do about this?
-
- Here is the solution:
-
- : TEST [ HEX ] FF . ;
-
- What we have done here is to use the special words "[" and "]" to force the
- word "HEX" to be interpreted and executed at once rather than compiled as
- part of the colon definition.
-
- Note that these are HeliOS words (not just square brackets around HEX) and
- require spaces on each side of the "[" and "]".
-
- Let us examine just what is happening here.
-
- The word ":" initially forces HeliOS to switch into "compile" mode while
- processing the code up to the terminating ";".
-
- As we know, normally this would cause the word HEX to be compiled.
-
- The word "[" forces HeliOS to switch back temporarily into "interpret" mode.
-
- Now the word HEX will be interpreted at once, changing the numeric base.
-
- The word "]" forces HeliOS to return to "compile" mode.
-
- The colon definition then continues compiling up to the final ";" as usual.
-
- Now try the new version of "TEST": it will work correctly without error.
-
- Interesting isn't it!
-
- You will learn more about this later...........
-
-
- -----------------------------------------------
- Computer Memory and more about the HeliOS Stack
- -----------------------------------------------
-
- Memory is the basic storage medium for program code and data.
-
- Memory can be thought of as a series of cells, each of which can hold a
- numerical value, and the way in which each value is interpreted is largely
- determined by the code within your program.
-
- HeliOS uses a special device called a STACK, which is actually just a small
- organised subsection of the large general memory pool. Rather than being
- randomly accessed in any order, the stack is accessed sequentially like a
- pile of boxes (containing information), or a deck of cards.
-
- Data is, in general, placed on the top of the stack and then removed when
- it is needed later.
-
- As more and more items are stored on the stack it grows in size, and the
- oldest items, those placed on the stack first, are left at the bottom.
-
- The HeliOS stack is employed to store sets of numbers which are going to be
- used almost at once by other subroutines, and can be regarded as a quick
- temporary store. It can also be looked upon as a "channel" of information
- between sequential operations. Typically one operation will put a number
- onto the stack, and the next will take the number off the stack and use it.
- You can think of it almost as a type of "messenger" carrying data between
- different parts of your program: a kind of "dumb waiter".
-
- Many HeliOS words, including your own program subroutines, look for and
- return values on the stack, and this process is called "parameter passing".
-
- Many would-be Forth programmers are initially terrified of using the stack
- because they have never used such a thing before and have perhaps used other
- languages which employ NAMED VARIABLES rather than a stack.
-
- Actually you will soon see that the stack is ridiculously easy to use and
- gives you a lot more programming power than the restrictive use of variables
- for all parameter passing. In HeliOS you can use the stack or you can use
- named variables, or both together: so you have more power and more choice.
-
- HeliOS provides a large number of words for manipulating the stack, and
- these should be learned as soon as possible - they will all soon become
- familiar since they are in constant use in ALL your HeliOS code. This is
- because you are constantly needing to adjust the position of data items
- on the stack, as well as adding, deleting, and duplicating items.
-
- Traditional Forth had just a few stack control words, and managed any more
- complex operations needed by combining many of these simple words together.
- Because the names used in Forth for stack operators are short and cryptic,
- complicated combinations of them are very unreadable. Not only this, but
- use of a lot of generalised words to do a job rather than one specific word
- is very inefficient. This was THE major problem with early Forth systems.
-
- This problem of "stack control" is one of the weakest parts of traditional
- Forth, and is largely responsible for Forth code getting a reputation for
- being quite unreadable. This is a shame, because Forth was potentially the
- most "readable" of all computer languages, and it was largely the limited
- stack control vocabulary of early Forth systems which caused the difficulty.
-
- HeliOS has removed the necessity for worry over stack manipulation by
- providing the most complete set of specialised words ever available in a
- Forth-type language. Try to gradually incorporate more and more of these
- words into your knowledge of HeliOS, so that you can use just the right
- specific word for the job rather than a series of less appropriate ones.
-
- HeliOS has adopted another totally new philosophy which departs from Forth
- tradition: all the stack control words in HeliOS are machine coded for
- maximum speed, so all are equally fast and efficient.
-
- We have dwelt perhaps overmuch on the stack, because the use of the stack
- will be really important throughout all of your HeliOS programming. The
- concept of always using the minimum of stack control words throughout your
- code is VERY important if your HeliOS programs are to be readable, easily
- maintained, and fast in operation.
-
- Before leaving this important subject, here is a very quick practical
- example of stack manipulation so that you can see what it is all about.
-
- Take a stack with four numbers on it: 1, 2, 3, 4
-
- Imagine that the "4" is at the top, and the "1" is at the bottom.
-
- Suppose that we want to duplicate the third number from the top and place
- a copy of it on the top of the stack.
-
- (Believe it or not, this sort of thing is quite commonly required!)
-
- So we need to operate on our initial stack to get: 1, 2, 3, 4, 2
-
- Let us assume that we have four stack operators:
-
- DUP - this duplicates the number on top of the stack
- eg. 1, 2, 3, 4 -> 1, 2, 3, 4, 4
-
- SWAP - this exchanges the top two stack items
- eg. 1, 2, 3, 4 -> 1, 2, 4, 3
-
- DSWAP - this exchanges the top two "double" stack items
- eg. 1, 2, 3, 4 -> 3, 4, 1, 2
-
- ROT - this REMOVES the third number on the stack and
- puts it onto the top
- eg. 1, 2, 3, 4 -> 1, 3, 4, 2
-
- How do we solve our simple problem?
-
- Why not try it as an exercise on paper?
-
- We could do the following: 1, 2, 3, 4
-
- ROT ->
- 1, 3, 4, 2
-
- DUP ->
- 1, 3, 4, 2, 2
-
- ROT ->
- 1, 3, 2, 2, 4
-
- DSWAP ->
- 1, 2, 4, 3, 2
-
- ROT ->
- 1, 2, 3, 2, 4
-
- SWAP ->
- 1, 2, 3, 4, 2
-
- Success! We did it! This way is slow, but it DOES work.
-
- (Actually it can be done quicker than this. Can you manage it?)
-
-
- But look......we have the following series of operators:
-
- "ROT DUP ROT DSWAP ROT SWAP"
-
- This is horrible to read, and even worse to debug when combined with a lot
- of other similar sequences. It is also very time consuming to compile and
- execute, since it takes SIX words to do one simple job. If we could do
- this operation in ONE word we should have SIX times better code - it is
- as simple as that.
-
- HeliOS would do the following in one word - and it would be a very fast
- internally machine coded word too.
-
- HeliOS would say: 1, 2, 3, 4
-
- 3PICK ->
-
- 1, 2, 3, 4, 2
-
-
- So we have used the special operator "3PICK" = "pick out the third item"
-
- We have written a program which compiles AND runs at least SIX times faster
- than the first method.
-
- This kind of thing is fundamental to good HeliOS programming, and you will
- constantly come up against coding tasks exactly like the above example.
-
-
- ------------------------
- The HeliOS stack display
- ------------------------
-
- To help you get accustomed to the working of the stack, HeliOS has a
- permanent stack display at the top of the Interpreter window.
-
- Try doing a few calculations and manipulations like the examples above
- and watch the stack display. This will soon give you a feeling for how
- the HeliOS stack works, because seeing the numbers change in the set of
- cells displayed graphically on screen is an excellent aid in visualising
- stack operations.
-
-
- ----------------------------------------------------------------
- Passing parameters between HeliOS Words and using Stack Diagrams
- ----------------------------------------------------------------
-
- Let us take, as a simple example, the HeliOS Word "FPENSET".
-
- This word sets the foreground text pen colour, which is simply a number.
-
- On a four colour screen text could be displayed in colour 0, 1, 2 or 3.
-
- Let us assume we are starting from an empty stack.
-
- Our word FPENSET needs to know what colour we want it to use, and this is
- done very simply in HeliOS by passing the colour number as follows:
-
- 1 FPENSET for "colour 1"
-
- or 3 FPENSET for "colour 3"
-
-
- Here the "parameter", the colour number, is "1" (or "3"), and is written
- in your source code as a simple number preceding the word FPENSET.
-
- This looks very natural and simple, and indeed this simplicity is a very
- good feature of HeliOS, but a little more is happening than is apparent.
-
- What actually happens is that the number "1" is stored on the stack until
- it is used by FPENSET, which leaves the stack empty.
-
- This situation can be represented by a device called a "stack diagram",
- which is simply a means of representing textually what happens to values
- on the stack during the operation of a HeliOS Word.
-
- You will see stack diagrams used throughout the HeliOS tutorials, and in
- particular they are a vital part of all Dictionary Word definitions.
-
- In the case cited above we would have a stack diagram as follows:
-
- ( n - - - )
-
- The "n" represents the colour number which the word FPENSET expects to
- find placed on the stack.
-
- The three "-" signs signify the "point in time" in the computing process
- when FPENSET does its work.
-
- The fact that there is no number afterwords means that FPENSET actually
- uses internally and removes its single parameter, leaving nothing on the
- stack itself.
-
- The parameter to be passed to the subroutine is stored temporarily on
- the stack, the subroutine then removes it and, in this case, returns
- with the stack clear.
-
- This type of method is crucial to HeliOS operation.
-
- Several parameters can be passed to subroutines via the stack, as you will
- see in the examples given below.
-
- The word GFXRECTFILL, for example, uses four parameters denoting the corners
- of a box to draw a filled rectangle.
-
- e.g.
-
- SCRCLR 6 GFXSETAPEN 100 100 120 120 GFXRECTFILL WAITSPACE SCRCLR
- ^ ^^^^^^^^^^^^^^^
- Single parameter Four parameters
-
- Many subroutines use the stack to return parameters, and your program
- must constantly keep track of the stack to ensure that this process of
- passing parameters is kept in order.
-
- The HeliOS words used to make ordinary arithmetic calculations all get
- their parameters from the stack, operate on them, and then return the
- result of the calculation on the stack.
-
- In a simple addition two parameters are needed, and the result, which
- is a single parameter, is returned on the stack -
-
- 3 5 + add two numbers 3 and 5, leaving the result on the stack
-
- . display on screen the value on the stack ( the "result" )
-
- The stack diagrams of these two words would be:
-
- "+" ( n1 n2 - - - n3 )
-
- "." ( n3 - - - )
-
-
- --------------------------------------
- Using 8-bit, 16-Bit and 32-Bit numbers
- --------------------------------------
-
- A computer deals with binary numbers, which are really just like sequences
- of simple two-state "on or off" switches. These switches are each said to
- contain one "bit" of information and can only represent the numbers 1 and 0.
-
- A single cell of memory contains an 8-bit number, which is a collection of
- 8 bits (or binary switches), and is called a "byte". This can represent a
- decimal number of up to "255", which is still a rather small unit of data.
-
- Because a byte is such a small "chunk" of information, we often use a much
- larger unit of 16-bits, or 2-bytes, which we call a "word".
-
- Above this we have 32-bit numbers which are 2 "words" or 4 bytes in length,
- and these are often referred to as "long" or "longwords".
-
- So....the data which we store is usually in the form of 1, 2, or 4 byte
- numbers.
-
-
- -----------------------
- Specifying number sizes
- -----------------------
-
- You will learn a lot more about numbers later, but it is important to know
- that HeliOS deals largely with the 3 standard number sizes which are defined
- in terms of their width in binary bits.
-
- We have:
-
- 8-bits = 1 byte
- 16-bits = 2 bytes = 1 word (in HeliOS this is called a "single number")
- 32-bits = 4 bytes = 1 longword (in HeliOS this is called a "double number")
-
- HeliOS refers to a 16-bit number as a "single number" because most HeliOS
- internal functioning runs in terms of 16-bit numbers, and a single stack
- cell is always 16-bits in size.
-
- Thus, any ordinary number which you type, in a program or at the command
- line, will be interpreted by HeliOS as a 16-bit number.
-
- What, then, do we do to enter and use "bytes" or "longwords"?
-
- Well, as far as "bytes " are concerned, you treat them exactly like 16-bit
- numbers: in fact HeliOS stores single byte data on the stack as a 16-bit
- number, even though this leaves one byte of the stack cell unused. There
- are functions to handle byte length numbers once they are "on the stack",
- but as far as number entry and stack storage is concerned a single byte data
- value is treated just like a 16-bit number.
-
- Longwords, or double numbers, are somewhat different, because these numbers
- actually take up 2 stack cells each. This means that HeliOS has to be told
- somehow, when you type in a number, that this is a double number and must
- be stored in 32-bit (4 byte) format.
-
- When you want to enter a number as a 32-bit double number you have to write
- the number in a special form so that the HeliOS interpreter can treat this
- number appropriately. This is done by including a "." character within the
- numeric expression.
-
- Here then, is a VERY important rule:
-
- * 32-bit numbers must be entered with a "." character ANYWHERE within the
- numeric expression.
-
- (This rule is actually a slight simplification, but it will suffice for
- now: we will go into more detail later.)
-
- For example, here are some ways of entering "double" 32-bit numbers:
-
- 123. .123 1.23 12.3 -.123 -1.23
-
- Note that the "." character merely tells HeliOS that this is to be treated
- as a 32-bit number, and is NOT necessarily a decimal point indicator.
-
- HeliOS does actually have a mechanism for reading decimal numbers, and it is
- possible to use the decimal point specifying the 32-bit number as a decimal
- place indicator. However, this is a more advanced topic and will be dealt
- with in a later tutorial.
-
-
- ---------------------------------------------------------
- Converting between differently sized numbers on the stack
- ---------------------------------------------------------
-
- Take careful note of the information in this section, since you will need
- to use it very often.
-
- Signed 16-bit data values can easily be converted from single (16-bit) to
- double (32-bit) size using the HeliOS word "S>D" ("single-to-double").
-
- However, signed 32-bit values can only be converted from double to single
- safely if they are less than 16-bit in numerical size: otherwise there
- will obviously be a truncation effect.
-
- Provided that a 32-bit signed number is of appropriate size, it may be
- converted to 16-bit size by simply dropping the top 16-bit cell from the
- stack.
-
- For example:
-
- -32 as a 16-bit number is stored on the stack as one cell : -32
-
- -32. as a 32-bit number is stored on the stack as two cells: -32 -1
-
- Dropping the -1 gives us just -32 on the stack, which is what we wanted.
-
- (Note that the top 16-bit stack cell holds the upper 16 bits of the 32-bit
- number, and see the documentation on signed and unsigned number represention
- in "Tutorial4" for an explanation of why this top cell is a 16-bit "-1".)
-
- Try this in the interpreter until you see clearly what is happening.
-
- Unsigned single numbers can be converted to double numbers by simply adding
- a zero to the stack, since this zero represents the high word of the new
- 32-bit value.
-
- In a similar way to the previous example with signed numbers, unsigned
- 32-bit numbers can sometimes (depending on number size) be converted to
- 16-bit values by simply dropping the top stack cell.
-
- For example:
-
- 32 as a 16-bit number is stored on the stack as one cell : 32
-
- 32. as a 32-bit number is stored on the stack as two cells: 32 0
-
- You can see from this how the conversion process in each direction would
- work.
-
- Again, you can experiment in the interpreter until you see clearly what is
- happening.
-
-
- -----------------------------------------------
- Using 16-Bit and 32-Bit memory addressing modes
- -----------------------------------------------
-
- Computers use numeric values to define positions in memory, often called
- memory "addresses", so that they know where to store and fetch information.
-
- On a machine like the Amiga, memory must normally always be "addressed" by
- 32-bit, or 4-byte "long" numbers.
-
- A 32-bit address is often referred to as a "long" address, or a "longword"
- address.
-
- HeliOS uses a little "trick" to avoid the use of these very large numbers
- all the time. It defines addresses within the HeliOS dictionary as 16-bit
- numbers and "internally" adds a further number (or "base address") to these
- addresses to get the true 32-bit address.
-
- Remember that HeliOS can actually use 16-bit addressing or 32-bit addressing
- depending on whether an address is in dictionary memory space.
-
- Note that:
-
- * 16-bit addressing can only be used for addresses within dictionary space.
-
- * 32-bit addressing can be used for addresses within ANY memory space.
-
- * Double word 32-bit addressing specifies a memory location directly as one
- large 4 byte long number, and this mode of addressing must ALWAYS be used
- in conjunction with Amiga library calls.
-
-
- ------------------------------------------------------------------
- The HeliOS Dictionary is a 16-bit addressed, 16-bit data structure
- ------------------------------------------------------------------
-
- What does this "imposing" statement mean?
-
- To keep things simple for now we should just point out that HeliOS uses
- 16-bit numbers for its standard mode of operation.
-
- Numbers on the stack are normally stored as 16-bit "cells".
-
- HeliOS stores 8-bit numbers on the stack also in a 16-bit cell, but ignores
- the top byte of the number.
-
- HeliOS stores 32-bit numbers on the stack as a "double" cell.
-
- A 32-bit number can sometimes conveniently be regarded as being stored on
- the HeliOS stack as two 16-bit cells, but there are many HeliOS commands
- which treat it conveniently and simply as a single unitary 32-bit entity.
-
- A 16-bit number is often referred to in HeliOS as a "single number".
-
- A 32-bit number is often referred to in HeliOS as a "double number".
-
- As well as using 16-bit data items as "standard", all memory addressing
- within the HeliOS dictionary memory space is usually specified by 16-bit
- numbers also (although any 16-bit HeliOS address can also be specified as
- a 32-bit address if required).
-
- In general then, HeliOS, like traditional Forth, is largely concerned in
- its internal operations with 16-bit numbers.
-
-
- ----------------------------
- A repeated IMPORTANT warning
- ----------------------------
-
- All normal Amiga addressing is 32-bit!
-
- 16-bit addressing is ONLY used to specify memory addresses within the main
- HeliOS dictionary.
-
- Remember always that this 16-bit addressing technique specifies a memory
- location as an offset from a point of reference which is the start of the
- HeliOS dictionary.
-
-
- ----------------------------------------------
- Converting between 16-bit and 32-bit addresses
- ----------------------------------------------
-
- Here are two HeliOS command words which translate between 16-bit and 32-bit
- addressing for any addresses within the HeliOS dictionary:
-
- W>L ( a1 - - - l1 ) -> Converts a 16-bit address to a 32-bit address
-
- L>W ( l1 - - - a1 ) -> Converts a 32-bit address to a 16-bit address
-
- Note that you MUST NOT attempt to convert 32-bit addresses which are not
- located within the HeliOS Dictionary space to 16-bit addresses.
-
-
- --------------------------------------------------------------
- How HeliOS specifies 16-bit and 32-bit addressing and numbers.
- --------------------------------------------------------------
-
- Addressing can be very confusing and people often get mixed up with 16
- and 32 bit data values and 16 and 32 bit addresses. To avoid confusion
- when using these differing quantities we need to use a regular notation
- and to keep a clear mental picture of just what all these different types
- of numbers represent.
-
- HeliOS uses a helpful standard form of notation, like this:
-
- 1. Word names have a "D" prefix when referring to double 32-bit data
-
- 2. Word names have an "L" suffix when referring to long 32-bit addressing
-
-
- ---------------
- Using Variables
- ---------------
-
- While HeliOS uses the stack for most of its "short term" parameter passing
- operations, ordinary memory can be used for data storage on a more long
- term basis. Languages like BASIC and PASCAL use named variables to access
- the memory in which the data is stored without involving the programmer
- with the actual "physical" memory address, or indeed with "stacks".
-
- HeliOS can do the same thing if required, and while the stack is much more
- efficient for most parameter passing (and gives HeliOS a significant speed
- advantage), there are many occasions where it is best to use variables.
-
- A variable can be created using the word VARIABLE and data can be moved in
- and out using the two HeliOS words "!" (which is pronounced "store") and @
- (which is pronounced "fetch").
-
- These two words operate very simply on a standard HeliOS 16-bit variable or
- indeed upon any 16-bit addressed memory within the HeliOS dictionary.
-
- Note that there are also variations on these simple "fetch" and "store"
- functions which allow you to operate on different data sizes and 32-bit
- memory addresses.
-
- For example:
-
- C! C!L C@ C@L -> Operate on 8-bit data
- ! !L @ @L -> Operate on 16-bit data
- D! D!L D@ D@L -> Operate on 32-bit data
- ^ ^
- The "L" signifies 32-bit memory addressing.
-
- There are many more memory accessing functions within HeliOS, and the main
- Dictionary documentation should be read carefully so that you are at least
- aware of all the various techniques available. This is an important topic.
-
-
- The word VARIABLE creates a 16-bit data 16-bit addressed variable, but you
- can have 8-bit and 32-bit data variables and 32-bit addressed variables:
-
- CVARIABLE -> 8-bit data 16-bit addressed
- VARIABLE -> 16-bit data 16-bit addressed
- DVARIABLE -> 32-bit data 16-bit addressed
-
- CVARIABLEL -> 8-bit data 32-bit addressed
- VARIABLEL -> 16-bit data 32-bit addressed
- DVARIABLEL -> 32-bit data 32-bit addressed
- ^
- The "L" signifies 32-bit memory addressing.
-
-
- Here is a VERY IMPORTANT thing to understand about HeliOS variables:
-
- * A variable in HeliOS is merely a named function which returns the 16-bit
- or 32-bit address of the memory location where the first byte of the
- variable's data is stored.
-
- For example:
-
- Memory cells
-
- |
- | A HeliOS 8-bit data variable
- | -----------------------------
- |
- One byte >X<-------- HeliOS variable returns this address on the stack
- of storage |
- (8-bit) |
- |
-
-
- |
- | A HeliOS 16-bit data variable
- | -----------------------------
- |
- Two bytes >X<-------- HeliOS variable returns this address on the stack
- of storage >X
- (16-bit) |
- |
-
- |
- | A HeliOS 32-bit data variable
- | -----------------------------
- |
- Four bytes >X<-------- HeliOS variable returns this address on the stack
- of storage >X
- (32-bit) >X
- >X
- |
-
-
- Here is a another VERY IMPORTANT feature of HeliOS variables:
-
- * All HeliOS variables are created and stored in the HeliOS Dictionary
- space, even if they are specified to return 32-bit addresses.
-
-
- This leads on to another interesting fact about variables:
-
- * All HeliOS variable addresses may be freely converted between 16-bit and
- 32-bit addressing modes.
-
-
- When a variable is created in HeliOS it always has to be initialised to a
- value, but if no particular initial value is needed you can always set the
- variable to zero to start with.
-
- A variable created in this way allocates Dictionary memory space and stores
- the new variable value along with header information.
-
- For example,
-
- 0 VARIABLE MILES
-
- will create a VARIABLE called "MILES" initialised to zero.
-
- In a similar manner,
-
- 50 VARIABLE MILES
-
- will create a VARIABLE called "MILES" and initialise it to 50.
-
- Note that the above examples create a 16-bit data variable stored in the
- 16-bit addressed HeliOS dictionary space.
-
- We can now get and display the memory contents referenced by the word
- "MILES" as follows:
-
- MILES @ . "miles-fetch-print"
-
- (or a shorter version: "MILES ?" which does exactly the same thing.)
-
-
- What is actually happening here?
-
- MILES \ Puts the address of the variable on the stack,
- \ or, more accurately, the address of the memory
- \ cell where the the value 50 is stored
-
- @ \ Gets the data stored at that memory address and
- \ puts it on the stack, having first removed the
- \ address from the stack
-
- . \ Displays and removes the "top of stack" value
-
- We have not specifically accessed memory numerically: we have just asked
- for the contents of the VARIABLE defined by the name "MILES".
-
- This use of easy to remember words (variable names) rather than numeric
- values (memory addresses) is a great help in writing easily understood code.
-
-
- Look how easy it is to store a value in a variable using "!" ("store"):
-
- 12 MILES ! "twelve-miles-store"
-
- This will store the value 12 in the memory location defined as "MILES".
-
-
- Both 16-bit and 32-bit data storage variables can be created as follows:
-
- 50 VARIABLE MILES
-
- Creates a 16-bit variable called 'MILES' and initialises
- it to 50.
-
- This variable is referenced by a 16-bit address.
-
- Use of the word 'MILES' puts a 16-bit address on the
- stack, specifying the memory location where the number
- 50 is stored as a 16-bit number in the HeliOS dictionary
- memory space.
-
-
- 50. DVARIABLE MILES
-
- Creates a 32-bit variable called 'MILES': the full stop
- after the "50" indicates that this is a 32-bit number.
-
- In this case the 32-bit data value is stored at a 16-bit
- address, and use of the word 'MILES' returns this 16-bit
- address where the 32-bit number "50." is stored.
-
- Note that the number 50 itself COULD be stored in an
- 8-bit space: the data size refers to the storage space
- and not the size of the actual number stored there.
-
- The D prefix signifies a double length data variable:
- remember this, as it is the standard form of notation.
-
-
- 50 VARIABLEL MILES
-
- Creates a 16-bit variable called 'MILES' stored in the
- Dictionary but referenced by a 32-bit or "Long" address.
-
- Use of the variable 'MILES' returns a 32-bit number on
- the stack representing the longword address where the
- 16-bit value is stored.
-
- The L suffix signifies a long address: note again that this
- is a standard notation for "long" 32-bit addressing.
-
-
- 50. DVARIABLEL MILES
-
- Creates a 16-bit variable called 'MILES' stored in the
- Dictionary but referenced by a 32-bit or "Long" address.
-
- Note the 32-bit data indicated by the "." after the "50"
- and the "D" prefix to indicate a 32-bit data variable.
-
- Note again the use of the "L" suffix to indicate the long
- addressing mode.
-
-
- The above example illustrates the standard HeliOS data and addressing size
- notation, which you should become familiar with as soon as possible.
-
-
- * The D prefix always relates to double length 32-bit data.
-
- * The L suffix relates to long 32-bit addresses.
-
-
- At risk of being over repetitious, it is important to remember that ALL
- variables are stored within the main HeliOS Dictionary, and can be 16-bit
- addressed or 32-bit addressed.
-
- Variables returning 16-bit addresses can have the 16-bit addresses converted
- to 32-bit addresses by using the HeliOS Word "W>L" ("word-to-longword").
-
- Variables returning 32-bit addresses can have the 32-bit addresses converted
- to 16-bit addresses by using the HeliOS Word "L>W" ("longword-to-word").
-
- Any address thus converted may be restored to its alternative form by using
- the reverse operation.
-
-
- ---------------------------------------
- Using "Text Strings" in HeliOS programs
- ---------------------------------------
-
- The term "String" is used in relation to text storage in memory: since
- computers only deal with numbers we have to represent text as a "string"
- of numeric codes in memory.
-
- Each text character is defined by a numeric code called an "ASCII" value,
- one byte in size, which is a standard code used for representing letters
- as numbers in the computer's memory.
-
- A series of continuous bytes in memory which represent text ("ASCII")
- characters make up a text "string".
-
- To handle text strings we need to know where they start in memory, and also
- where they stop (or how long they are). This is accomplished by using two
- different conventions which are each useful in different circumstances.
-
- Strings are handled either as:
-
- 1. "Counted Strings".
-
- These are always stored in a special format with a single "count" byte
- at the first position in the string. This "count" byte specifies the
- length of the string in terms of its actual text character count, which
- can only be up to 255 characters in length. These strings are commonly
- used in FORTH systems, and are generally quick and easy to handle, but
- they are not used by the Amiga operating system and library functions.
-
- 2. "Null-terminated Strings"
-
- These strings include no size information, and simply start at the
- string address with the first text character. The length of the string
- is determined by specifying its end point, which is defined by placing
- a "null" or "0" character after the last text character. These strings
- can be any length, and are generally used as the standard string format
- by Amiga operating system functions and library calls.
-
- Important note:
-
- * In HeliOS all counted strings also have a terminating "null", allowing
- them to be used as uncounted strings by using the first actual text
- character as the string start after skipping past the "count" byte.
-
- In both types of string a memory address is used to specify the start of the
- string, and this address value is used as a "handle" when manipulating the
- string.
-
- As with numeric data a string "address pointer" can be used as a simple
- number on the stack, or may be "named" like a variable.
-
- HeliOS has functions for creating and handling string variables, and these
- are similar and equivalent to the functions for numeric variables.
-
- Remember these points:
-
- * The first byte of a counted string is always called the "count byte" and
- holds a single-byte number specifying the total number of text characters
- in the string.
-
- * Counted strings have limited length, since the single "count" byte has a
- maximum value of 255.
-
- * In the case of the "null terminated" string the first byte of the string
- is simply the first character of the string itself, which continues on in
- memory until a null value "0" occurs: hence its name.
-
- * Null terminated strings can be of any length.
-
- * Traditionally Forth used counted strings, but the Amiga operating system
- uses null terminated strings.
-
- * HeliOS has comprehensive support for both counted and uncounted strings,
- including easy functions for conversion from one type to the other.
-
- * HeliOS has the extra useful feature that all counted strings all have a
- terminating null also. To access a counted string as "null terminated"
- all you have to do is increment the address of the string by one, thus
- moving forward past the initial "count" byte to the first character.
-
- HeliOS has a large number of string handling routines, many of which handle
- either 16-bit or 32-bit addressed strings.
-
- As a general rule, you can handle all strings as 16-bit addressed in simple
- programs where you are using the Dictionary memory for string storage.
-
- It is also usually a good idea to use counted strings where possible, since
- these are generally easier to use and have more powerful string manipulation
- functions.
-
- However, if you need to pass any string to an Amiga library function you
- will need to convert the string to 32-bit addressed using "W>L", and you
- will also need to make sure that you specify the string in uncounted form.
-
- Remember that you can simply add 1 to the string address pointer to convert
- a counted string to an uncounteed string for an Amiga library call.
-
- Note here that in this case the string itself is still left unchanged, and
- remains stored as a counted string in memory: it is merely the POINTER to
- the string which you change when passing it to the Amiga library call.
-
-
- --------------------------------------------------------------
- A very simple and useful HeliOS string handling word - "LIT$".
- --------------------------------------------------------------
-
- The word LIT$ can only be used within colon definitions.
-
- LIT$ is used within a colon definition to allow compilation of a counted
- string within your program code. The text string itself must be enclosed
- between two dollar ("$") characters, as this example shows:
-
- : PRESSMESSAGE LIT$ $Press SPACE-BAR To Continue$ ;
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Text string
-
- This example creates a new word PRESSMESSAGE, which employs "LIT$" to store
- the text between the two dollar characters ("Press SPACE-BAR To continue")
- within the dictionary.
-
- When you later use the word PRESSMESSAGE the 16-bit address of the counted
- string will be returned on the stack.
-
- It can then, for example, be printed out to the screen using the word "$."
- in another word as follows:
-
- : SHOWPRESMESSAGE PRESSMESSAGE $. ;
-
- You will find this little word "LIT$" VERY useful indeed: we use it in the
- example program below, and you should learn to use it yourself in your own
- programs as soon as possible.
-
- There is also a 32-bit version of LIT$ called LIT$L, which returns a 32-bit
- string address on the stack at run time, instead of a 16-bit string address.
-
-
- -------------------------------------
- General INPUT and OUTPUT using HeliOS
- -------------------------------------
-
- Obtaining User Input:
-
- HeliOS has a general purpose user input interrogation word, called "KEY".
-
- This word "KEY" causes a program to wait for user input, then it returns a
- code on the HEliOS stack defining exactly what type of input event occurred.
-
- Input events include keyboard entries, menu selections, mouse button clicks,
- mouse movement, gadget selection, menu selection, ticker activation etc..
-
- HeliOS uses the word "KEY" because traditional Forth used this word, but
- in Forth this word only accessed keyboard events, unlike the much extended
- HeliOS version which handles ALL Intuition graphical user interface events.
-
- The user input word "KEY" will report input events from whatever active
- Intuition window you specify.
-
- You must tell HeliOS which window to check for user input by specifying a
- current input window using the HeliOS word "MAKEINWINDOW".
-
- MAKEINWINDOW is an immensely powerful and important word, as it actually
- runs a separate Amiga task dedicated to handling user input in designated
- Intuition widows.
-
- The MAKEINWINDOW command sets up a very extensive program to handle all
- types of user input, which in any other Amiga language you would have to
- write for yourself.
-
- This event reporting program running from its own Amiga task translates all
- input events into whatever form the main HeliOS program requires, and has
- many very sophisticated features unique to HeliOS.
-
- All this power translates, from your point of view, to the easy use of the
- single word "KEY": all the hard work is done for you, and most of the time
- you never need be concerned with the underlying mechanism.
-
- You can learn more about these functions in the "Dictionary.doc" and in
- the later tutorials.
-
-
- ------------------------------------------------------
- Sending text output to the user via the screen display
- ------------------------------------------------------
-
- There are two basic types of screen text output:
-
- 1. Console text output
-
- This is a method of outputting text to a special text handling program
- called a "console" which allows various auto-formatting facilities etc.
-
- Text characters are, in HeliOS, usually written to console windows using
- a system of streams, which have full scrolling, cursor movement, and text
- formatting facilities etc.
-
- In general all dynamic, changing text output is handled by "console" type
- displays.
-
- 2. Graphic text output
-
- This is a method of outputting text in simple graphical form, as a
- series of letters represented by graphical symbols, without any form
- of control or formatting.
-
- Graphic text output does not have any "text control" features and all
- text is placed on the screen as a static graphic "drawing". This means
- that, for example, text can only be deleted by overwriting the screen
- area occupied by the graphic image of the text.
-
- In general graphic text output is used for "painting" a graphic display
- with static text.
-
- Both kinds of text are fully supported by HeliOS, but the following
- simple examples use "console" text output for simplicity.
-
- Note that this console output is not always simple on the Amiga, and in
- other languages quite a lot of programming is required to set up console
- output.
-
- HeliOS is unique in the power of its automated text console functions, and,
- as you will see, console text output has been made very easy indeed.
-
- As a matter of interest, HeliOS has two powerful sub-programs which fully
- automate the setting up of:
-
- 1. Sophisticated console text output
-
- 2. Comprehensive Amiga graphic library graphical operations
-
- within ANY designated window on ANY screen.
-
- Quite large programs would have to be written by you in any other language
- to achieve this functionality of HeliOS, which requires you to use just one
- word to set up each sub-program.
-
- Here are the two important HeliOS output configuration functions:
-
- 1. MAKOUTWINDOW - Sets up a very sophisticated console handling system
- with 10 automated text "streams".
-
- This word is used to attach a text output console to a
- window and make this the current text output window.
-
- This works with any Intuition window.
-
- 2. MAKEGFXWINDOW - Sets up an automated graphics library handling system
- with single word operators for most graphic functions.
-
- This word is used to set up all HeliOS graphic output
- commands for a window and make this the current graphic
- output window.
-
- This works with any Intuition window.
-
- Our final example program below will show you how to use these functions,
- and later tutorials will explain more about them.
-
-
- --------------------------------------
- A simple tutorial programming exercise
- --------------------------------------
-
- Now let us look at a simple programming exercise.
-
- Our next short tutorial program will start with a line of code which clears
- all words from the user dictionary, leaving just the CORE vocabulary.
-
- This is a useful way to start any HeliOS program, since it ensures that the
- system is clear each time you compile the program.
-
-
- FORGET **CORE** \ Get rid of any old USER defined words
-
-
- The "\" character denotes an "end of line comment", and anything following
- this is ignored by the compiler. Always add plenty of descriptive comments
- to your code in this way, so that you know what is going on.
-
- Remember here that ALL words in HeliOS source code need a space before and
- after them. This is absolutely vital, and note that a space is also needed
- both before and after the "\" character, because this is also a HeliOS Word.
-
- To summarise these points, the above line of code has:
-
- At least one space
-
- The word "FORGET"
-
- At least one space
-
- The word "**CORE**" telling FORGET to clear all words back to CORE
-
- At least one space
-
- The word "\" which tells us that the rest of the line is a comment
-
- At least one space
-
- The words "Get rid of any old USER defined words" (the comment)
-
-
- Now we will add a "colon definition" to our program.
-
-
- FORGET **CORE** \ Get rid of any old USER defined words
-
- : SAYHELLO ." HELLO WORLD" ; \ Make a word called SAYHELLO
-
-
- The colon definition above will create a new subroutine called SAYHELLO.
-
- Let us look at it's structure. It has:
-
- At least one space
-
- A ":" to start the definition
-
- At least one space
-
- A descriptive function name -> "SAYHELLO"
-
- At least one space
-
- The definition -> ." HELLO WORLD"
-
- At least one space
-
- A ";" to finish the definition
-
- At least one space
-
- A "\" which tells us that the rest of the line is a comment
-
- At least one space
-
- The words "Make a word called SAYHELLO" (the comment)
-
-
- We now have a complete small program:
-
-
- FORGET **CORE** \ Dispose of any old USER defined words
-
- : SAYHELLO ." HELLO WORLD" ; \ Make a subroutine called SAYHELLO
-
-
- Let us examine the definition of SAYHELLO, which is:
-
- ." HELLO WORLD"
-
-
- This can be analysed into three parts as follows.
-
- <SPACE> ." <SPACE> HELLO WORLD "
- ^^ ^^^^^^^^^^^ ^
- Function Text Delimiter
-
-
- The first part is the HeliOS word ." which tells the HeliOS system to output
- to the screen the words following it up to the next " character.
-
- The second part is the expression HELLO WORLD, which is the message we want
- to display.
-
- The third part is the quote character " which tells the HeliOS system that
- our enclosed quotation has ended.
-
- The double quote " is not a HeliOS WORD and does not need a space before it:
- it is called a delimiter and merely acts to delimit the end of an enclosed
- text message "string".
-
- To use the new word (or subroutine) all we need to do is either type its
- name at the command line after compiling our program, or include its name
- in our program code.
-
-
- --------------------------------------
- Entering and compiling our new program
- --------------------------------------
-
- There are two main ways of entering code.
-
- We can either use an editor, or we can type in code at the the command line.
-
- The editor option is perhaps better in most cases because code can be saved
- to, and loaded from, disk files.
-
- However, the command line is very quick and convenient, and has a circular
- "history" buffer, making it useful for testing small fragments of code which
- are being continually modified.
-
- The command line "history" buffer allows you to use the up/down cursor keys
- to bring back any previously typed command lines and reuse them.
-
- In general the command line is very useful for small code testing jobs, but
- cannot be saved to disk and is clumsy for entering larger code sections.
-
- We will use an editor in this tutorial example, as follows:
-
- 1. Click one of the "Ed x" buttons at the top of the screen to enter an
- empty editor (use the "Clear text" menu option if necessary).
-
- 2. Now type in the following code:
-
- FORGET **CORE** \ Dispose of any USER defined words
-
- : SAYHELLO ." HELLO WORLD" ; \ Make a word called SAYHELLO
-
- SAYHELLO \ Use the new word we have created
-
- WAITSPACE \ Wait for the space bar to be pressed
-
- 3. Then compile the code in the editor (you can use <Ctrl-5>).
-
-
- This action will take you into the Interpreter and run the program.
-
- Typing in the text is a worthwhile exercise, since it helps familiarise
- you with the process of entering source code.
-
- However, you can always use the cut and paste functions if you like, or
- even, if you wish, you can simply run the code directly by using <Amiga-e>
- after highlighting the text in this editor.
-
-
- Our little program above actually does something: it will print to the
- screen the message "HELLO WORLD".
-
- Note that you can now type SAYHELLO at the command line and the message
- "HELLO WORLD" will appear on screen.
-
-
- The next thing to do is save your new program source code to a disk file:
-
- 1. Re-enter the editor containing your code.
-
- 2. Select "Save As" from the "Load/Save" menu to access the HeliOS File
- Requester.
-
- 3. Save the file with a name and path of your choice.
-
- Note that each time you resave a file with the same name as before
- HeliOS will create a backup file for you automatically.
-
- Having created and saved a small working program, we can now start to do
- some more interesting things with it.
-
- Listed below are a number of variations on our program for you to try.
-
- Some of the examples below use HeliOS functions which you may not yet be
- familiar with: nevertheless they are quite easy to follow, and you should
- be able to make sense of what is happening.
-
- Things such as DO...LOOP constructs and the use of Return stack functions
- will be explained in later tutorials, but for now you should look at the
- examples given and try to get the general idea of how things work.
-
- Use the editor again to modify the code you have already entered, then use
- the methods outlined above to save and execute your code.
-
- Note that you can omit the comments if you like.
-
- Try each of the following variations:
-
-
- : SAYHELLO \ This version changes the output text position
-
- 10 10 CURPUT \ Set the text output position ("PUT" the "CURSOR")
-
- ." HELLO WORLD" \ Say hello
- ;
-
-
- : SAYHELLO \ This changes the output text position and colour
-
- 6 FPENSET \ Set the foreground pen - text colour
- 7 BPENSET \ Set the background pen - text background
- 10 10 CURPUT \ Set the text output position ("PUT" the "CURSOR")
-
- ." HELLO WORLD" \ Say hello
- ;
-
-
- : SAYHELLO \ This displays the message 4 times in line
-
- 4 0
- DO \ Loop 4 times
- ." HELLO WORLD" \ Say hello
- SPACE \ Put a space between messages
- LOOP
- ;
-
-
- : SAYHELLO \ To display the message 4 times on new lines
-
- 4 0
- DO \ Loop 4 times
- CR \ "Carriage Return" = Go to start of next line
- ." HELLO WORLD" \ Say hello
- LOOP
- ;
-
-
- Now for a more elaborate one........
-
-
- : SAYHELLO \ This repeats the message 4 times on new lines
- \ in a box
-
- SCRCLR
-
- 6 FPENSET \ Set the foreground pen - text colour
- 7 BPENSET \ Set the background pen - text background
-
- 7 GFXSETAPEN \ Set the graphics drawing colour (box colour)
- 1 GFXSETOPEN \ Set the graphics outline pen colour (box outline)
-
- 1 GFXOUTLINE \ Switch on graphics OUTLINE mode
-
- 10 \ Pixel "x" pos of the box's top left hand corner,
- \ measured from top left hand corner of screen
- 45 \ Top left "y" pos
- 150 \ Bottom right "x" pos
- 90 \ Bottom right "y" pos
- GFXRECTFILL \ Draw a filled rectangle (draw box)
-
- 0 GFXOUTLINE \ Switch off graphics OUTLINE mode
-
- 4 0
- DO \ Loop 4 times
- CR \ "Carriage Return" = Go to start of next line
- 4 CURFW \ Move the "CURSOR FORWARD" to give a margin
- ." HELLO WORLD" \ Say Hello
- LOOP
- WAITSPACE
- ;
-
-
- And now an even more elaborate one........
-
-
- : SAYHELLO \ This repeats the message 4 times on new lines
- \ in a box
-
- SCRCLR
-
- 6 FPENSET \ Set the foreground pen - text colour
- 7 BPENSET \ Set the background pen - text background
-
- 7 GFXSETAPEN \ Set the graphic drawing colour (box colour)
- 1 GFXSETOPEN \ Set the graphics outline pen colour (box outline)
- 1 GFXOUTLINE \ Switch on graphics OUTLINE mode
-
- 10 \ Pixel "x" pos of the box's top left hand corner,
- \ measured from top left hand corner of screen
- 45 \ Top left "y" pos
- 150 \ Bottom right "x" pos
- 90 \ Bottom right "y" pos
- GFXRECTFILL \ Draw a filled rectangle (draw box)
-
- 0 GFXOUTLINE \ Switch off graphics OUTLINE mode
-
- 4 0
- DO \ Loop 4 times
- 4 \ Start at 4th position on line
- I 2 + \ Start at 2nd line + LOOP INDEX
- CURPUT \ PUT the CURSOR
- ." This is line " \ Print "This is line"
- I 1+ \ Increment the LOOP INDEX + 1 which is stored
- \ on the stack, (the index starts at 0)
- . \ Print the index number (stored on the stack)
- LOOP
-
- WAITSPACE
- ;
-
- Look at these various examples and try changing things until you are quite
- familiar with the general process of editing, saving and compiling.
-
- **************************************************************************
-
- ----------------------------------------
- Using Amiga Libraries from within HeliOS
- ----------------------------------------
-
- Amiga Libraries are special code modules which are provided to help you
- with various programming tasks, and are very simple to use.
-
- Libraries are either present within the Amiga ROM (Read Only Memory), or
- may be automatically loaded from disk.
-
- The overall method of accessing a library is:
-
- 1. OPEN the library The Amiga loads and prepares it for use
-
- 2. CALL library routines You will need a reference book for definitions
-
- 3. CLOSE the library When you have finished with it
-
-
- Functions accessing many of the more frequently required Amiga ROM library
- routines are included in HeliOS as part of the CORE dictionary.
-
- These functions are effectively pre-written "interfaces" to specific Amiga
- library calls and do not require you to address the library directly.
-
- In addition, the main and most useful libraries are automatically opened for
- you when HeliOS starts up and closed when HeliOS closes down.
-
- These are the DOS, EXEC, GRAPHICS, LAYERS, and INTUITION libraries.
-
- If you do have to open a library yourself there is a simple to use HeliOS
- word called OPENLIB, which opens a library and returns the 32-bit library
- base address on the stack.
-
- Once you have opened a library you must always store the 32-bit library base
- address in a standard HeliOS DVARIABLE for use later by the HeliOS library
- calling function.
-
- When you have finished with the library you should always use the HeliOS
- CLOSELIB function to close it down.
-
- As an example we will show how to open "diskfont.library".
-
- First we need to initialise a DVARIABLE to store the library base address
- when we have opened the library.
-
- 0. DVARIABLE DFONTBASE \ Create a 32-bit variable DFONTBASE
-
-
- Now we open the library and store the library base address.........
-
- LIT$ $diskfont.library$ \ Put counted library name string on stack
- 0 \ Put library revision number on stack
- OPENLIB \ OPEN the library
- DFONTBASE D! \ Store the library handle
-
-
- Having attempted to open a library, you should always check to see that the
- returned library base is not zero, in which case the library has failed to
- open for some reason and you need to sort out the problem.
-
- Something like this:
-
- DFONTBASE D@ D0<>
- IF
- ..........etc.
-
- -----------------
- Closing a library
- -----------------
-
- To close a library all you have to do is put the library base address on
- the stack and use the word CLOSELIB, like this:
-
- DFONTBASE D@ CLOSELIB
-
- That's all there is to it!
-
- Important notes:
-
- * Remember that you only need to close the libraries which you yourself
- have specifically opened.
-
- * You do not need to close (and MUST not close) the standard libraries
- handled for you by HeliOS system.
-
- ---------------------
- Making a library call
- ---------------------
-
- When a library is open, and you want to use it, you need to know how to
- specify parameters and call individual library routines.
-
- HeliOS has a very simple library calling mechanism which is very similar to
- the methods used for assembly language.
-
- When you are looking up library functions in general Amiga documentation
- you should always consult the information referring to assembly language
- library calls: this information can be used directly in HeliOS.
-
- If you look at the Amiga library documentation you will see that there are
- instructions for assembly language library calls, telling the programmer in
- which MC680xx microprocessor registers to store parameters.
-
- You can gather from this that in assembly language you store parameters
- directly into the registers within the MC680xx microprocessor before calling
- a library.
-
- The results of library calls are also stored in these MC680xx registers when
- the library call has been completed.
-
- Don't worry if this sounds difficult - it is actually very easy!
-
- The MC680xx has a set of 8 ADDRESS registers, labelled A0-A7, and a set of
- 8 DATA registers, labelled D0-D7: these registers are all 32-bit registers.
-
- Your library documentation will tell you to:
-
- Put a certain parameter value into register A0
- Put a certain parameter value into register D0
- etc.
- etc.
-
- Call a Library function at a certain specified offset from the library base
-
- Read result of call from register D0
- etc.
- etc.
-
-
- Here, then, is what you need to know before calling a library function:
-
- 1. What is the library base offset for the routine you wish to call?
-
- This is found from Amiga documentation and will always be a negative
- number.
-
- You can use an include symbolic value if you wish.
-
- 2. What "parameters" does that library call require before using it?
-
- These details are found in Amiga library documentation, and you
- need to look for MC680xx register useage, as with assembly language
- library calls.
-
- 3. What results are returned after completion?
-
- These details are found in Amiga library documentation, and you
- need to look for MC680xx register useage, as with assembly language
- library calls.
-
-
- So, how do we use this information to make a library call in HeliOS?
-
- As we said, HeliOS is very close to assembly language in operation, so it
- handles library calls in a manner closely reflecting the way it is done in
- assembly language, by storing parameters in MC680xx registers.
-
- But, you might ask, how can we use MC680xx registers from within HeliOS?
-
- Well, to translate this type of operation into HeliOS is very easy because
- you have a set of DUMMY MC680xx registers in which to store your parameters
- and read your results.
-
- The DUMMY ADDRESS REGISTERS are accessed as double number (32-bit) variables
- by putting the register number you require on the HeliOS stack and then
- using the word AREG to return the variable address.
-
- For example:
-
- 0 AREG -> Returns 16-bit address of 32-bit data store for DUMMY A0 register
- 1 AREG -> Returns 16-bit address of 32-bit data store for DUMMY A1 register
-
- etc.
-
- The same method applies to DUMMY DATA REGISTERS but this time you use the
- word DREG.
-
- For example:
-
- 0 DREG -> Returns 16-bit address of 32-bit data store for DUMMY D0 register
-
- When HeliOS calls a library for you, using the HeliOS Word LIBRARY, it
- simply unloads the dummy registers into the actual MC680xx processor
- registers, calls the library, then unloads the MC680xx registers back
- into the dummy registers.
-
- Notice that this technique is doubly useful, because it means that all the
- values in the dummy registers are automaticaly stored and retained for your
- use until the next time you prepare a library call or reset the registers.
-
-
- To carry out the example library call given above you would:
-
- Put a certain parameter value into HeliOS DUMMY MC680xx register A0
- Put a certain parameter value into HeliOS DUMMY MC680xx register D0
- etc.
- etc.
-
- Call HeliOS LIBRARY function with specified offset
-
- Read result of call from HeliOS DUMMY MC680xx register D0
- etc.
- etc.
-
-
- To do this in actual Helios code you might write something like this:
-
- PARAMETER1 D@ \ Get parameter onto stack
- 0 AREG D! \ Store it in DUMMY ADDRESS REGISTER A0
-
- PARAMETER2 D@ \ Get parameter onto stack
- 0 DREG D! \ Store it in DUMMY DATA REGISTER D0
-
- LIBRARYBASE \ Put address of Library base store onto stack
- -64 \ Get library offset onto stack
- LIBRARY \ Call library
-
- 0 DREG D@ \ Get result from DUMMY DATA REGISTER D0 onto stack
-
- Remember, the dummy registers will always directly reflect their MC680xx
- counterparts before and after the library call.
-
- The word LIBRARY which makes the call is not at all complicated, you simply
- put the name of the variable where the library base address is stored onto
- the stack, followed by the library routine offset, then use the word
- LIBRARY exactly as shown above.
-
- Note that it is not the library base pointer itself that is used by the
- word "LIBRARY" but a 16-bit HeliOS storage variable address (the reason
- for this is that this arrangement gives slightly faster performance).
-
- That is all there is to calling Amiga libraries, except for one last thing
- which makes your task even easier.
-
- In the above code we have accessed the result of the library call in dummy
- register D0 quite correctly by using the code sequence "0 DREG D@".
-
- However, because this code sequence is used very often, HeliOS includes an
- easy single word alternative "D0RESULT".
-
- * Instead of typing "0 DREG D@" you can simply type the one word "D0RESULT"
- to get the value in DUMMY REGISTER D0.
-
-
- --------------------------------------------------
- Making a call to external assembler-generated code
- --------------------------------------------------
-
- You may wish at some point to include assembly language sections within
- your HeliOS programs.
-
- You can do this in three ways:
-
- 1. Using the HeliOS integrated assembler.
-
- This is OK for simple sections of in-line assembler code, but is more
- clumsy to use than a fully featured separate dedicated assembler.
-
- 2. Creating an Amiga library by writing code in an assembler and then using
- a utility such as the PD program "LibTool" to generate an Amiga library
- from your code.
-
- This new library can then be called like any other library from HeliOS.
-
- 3. Creating an executable program in an assembler and then executing it
- from within HeliOS.
-
- This third method is a very efficient and easy way of accessing assembler
- code from within HeliOS, and we will now discuss it in more detail.
-
- Firstly you need to generate an assembly language program with all the
- components which you want to access from HeliOS defined in an initial
- table, like this:
-
- dc.l MyRoutine1
- dc.l MyRoutine2
- dc.l MyRoutine3
- dc.l MyRoutine4
-
- MyRoutine1 move.w etc. etc.
- move.w etc. etc.
- rts
-
- MyRoutine2 move.w etc. etc.
- move.w etc. etc.
- rts
-
- etc. etc.
-
- Remember to create the initial longword reference table at the start of
- the assembler program code because you will need to use this from within
- HeliOS to access the individual parts of your program.
-
- Assemble the program into an executable file, and then you can load it
- into memory from within HeliOS using the DOS LoadSeg/UnLoadSeg routines,
- which allow you to load an external program into memory.
-
- Here is a short example of how you might do this:
-
- \ First set up some storage facilities......
-
- 0. DVARIABLE Load_SegList \ Loaded SegList BPTR
- 0. DPOINTER Load_CodePtr \ Pointer to loaded code
-
- \ Load your code......
-
- : Code_LoadSeg
-
- LIT$ $Code.exe$ W>L D1+ \ Uncounted filename
-
- 1 DREG D! \ -> Reg D1
-
- _LVOLoadSeg DOSBASE LIBRARYL \ Call DOS "LoadSeg"
-
- D0RESULT D0= ERROR" Error!" \ Error check
-
- D0RESULT
- DDUP Load_SegList D! \ Store SegList
- 2 DLSL \ Convert BPTR to APTR
- 4. D+ \ Get code start offset
- Load_CodePtr MAKEPOINTER \ Set up pointer
- ;
-
- \ Don't forget a routine to unload your code when you are done......
-
- : Code_UnLoadSeg
-
- Load_SegList D@ 1 DREG D! \ SegList -> Reg D1 ; SegList -> Reg D1
- _LVOUnLoadSeg DOSBASE LIBRARYL \ Call DOS "UnLoadSeg"
- ;
-
- Having loaded your code into memory using "Code_LoadSeg", it is very easy
- to call any routine with the code from your HeliOS program.
-
- To do this you would use the HeliOS "JSR" function.
-
- Assuming that your routines withing the external assembler code are listed
- in order at the start of the code, you can access any of them like this:
-
- : Code_RunExt \ ( Routine number (w) - - - )
-
- 4 m* Load_CodePtr D+ D@L \ Get routine pointer from initial table
- JSR \ JSR to loaded code routine
- ;
-
- The "JSR" function will automatically handle the interfacing of HeliOS
- to the assembler code, and parameters are passed using the HeliOS dummy
- MC680xx registers, exactly as with HeliOS library calls.
-
- This means that whatever values you set into the dummy registers (using
- AREG and DREG) will be stored in the actual MC680xx registers before the
- JSR function enters the machine code routine.
-
- Of course the dummy registers also return with the actual MC680xx register
- values when your assembpler code does a final "RTS".
-
- As you can see, this is a very simple (and powerful) method of accessing
- external assembler code.
-
-
- ----------------------------------------------------
- General procedures for Starting and Closing programs
- ----------------------------------------------------
-
- It is a good idea to stick to a regular procedure (hopefully a good one)
- when writing all your programs. Especially in code which starts and closes
- down your programs, it is possible and desirable to use a standard set of
- prewritten subroutines which can be modified as required.
-
- There are several rules that you should follow to produce good, safe code.
-
- 1. Always try to mirror opening and closing calls.
- 2. Always try to have ONE universal and thorough exit point.
- 3. Always make sure you close down everything you open, especially memory.
- 4. Always make sure to initialise variables correctly in RUN-TIME code.
- 5. Always check the memory available before and after using a program: if
- you are losing memory something is very wrong.
- 6. Always arrange your own output screen/window for serious programs. You
- can't use the interactive HeliOS window in stand-alone compiled code,
- for the simple reason that it won't be there!
-
-
- It is a good idea to use standard start-up and close-down words for all
- your programs.
-
- Any special functions needed for particular programs may be handled as
- single extra subroutine calls rather than all the startup and closedown
- code being changed.
-
- We include below simple source code for a program which:
-
- 1. Has a simple structured "startup" word definition and a corresponding
- "closedown" routine: you can modify these for your own purposes and it
- would be a good idea to use them as a basis for all your early programs.
-
- 2. Opens a custom screen
-
- 3. Opens a window on the new screen
-
- 4. Sets up graphic output to the new window and draws some graphics,
- including "graphic text"
-
- 5. Sets up console text output in the new window and prints some text
-
- 6. Sets up user input from the new window and waits for <SPACE> to
- be pressed.
-
- 7. Uses an Amiga library call to show how it is done.
-
- 8. Illustrates many of the concepts we have been discussing above......
-
-
- You will be surprised, perhaps, to see how easy all this is, and certainly
- you will be amazed how easy it is if you have used other Amiga programming
- languages which require you to do an enormous amount more preparatory work.
-
- **************************************************************************
-
- Note:
-
- The following program is provided as a disk file called "Tutorial.Src".
-
- You can load this program into the HeliOS editor, as described for the
- small tutorial programs given earlier, then compile and run it.
-
- However, the code is included here so that you can read through it in
- the context of this tutorial.
-
- **************************************************************************
-
- --------------------------------------
- A typical "universal" start up program
- --------------------------------------
-
- A typical start up program section might be as follows:
-
- FORGET **CORE** \ Clear the user dictionary
-
- 0. DVARIABLE SCREEN \ New Screen handle storage variable
- 0. DVARIABLE WINDOW \ Window handle store
-
- 0. DVARIABLE BITMAP \ Variables to store useful values, which.
- 0. DVARIABLE RASTPORT \ are collected at startup time in case of
- 0. DVARIABLE VIEW \ the need to use them later in graphics
- 0. DVARIABLE VIEWPORT \ related functions.
-
-
- \ OPENSYSTEM - Opens a screen and a window and sets up Input/Output.
- \ Includes an example of a library call for you to see
- \ Returns "1" on the stack for success and "0" for failure
-
-
- : OPENSYSTEM \ Start a colon definition, the new word is
- \ called, appropriately, "OPENSYSTEM"
-
- TIMEOFF \ Disable the time display in the HeliOS screen
-
- 0 HISTORY \ Disable the line editor's circular buffer
-
- 1 BAKSET \ Enable creation of Backup files on all disk
- \ SAVE operations - a useful safety feature
-
- \ These are all "general purpose" startup operations often used
-
-
- 1 STDSCREEN \ Initialises a standard NewScreen structure
- \ and sets Hires mode
-
- LIT$ $Tutorial Screen$ \ Specify the screen title bar text
-
- 640 250 \ Specify screen width and height
-
- 3 \ Depth of screen = number of bit planes
-
- OPENSCREEN \ Open a screen using the initialised structure
-
- SCREEN D! \ Store the screen handle/pointer
-
- SCREEN D@ \ Get SCREEN 32-bit pointer onto stack
-
-
- D0> \ Test if SCREEN is greater than zero
- \ This checks to see if screen opened OK
- \ If SCREEN is zero we have trouble.......
-
- IF \ If SCREEN is not zero we are OK.........
-
- SCREEN D@ \ Get 32-bit pointer to screen
-
- 44. \ Put double length number 44 on stack
-
- D+ \ Add this to screen pointer to give
- \ ViewPort pointer
-
- VIEWPORT D! \ Store the ViewPort for the new screen
-
- STDWINDOW \ Initialise a standard NewWindow structure
-
- HFWINDOW \ Modify the standard window for it to appear
- \ on the HeliOS Screen
-
- SCREEN D@ \ Get new screen again
-
- WINDOWSTRUCT \ Returns 16-bit pointer to NewWindow
-
- 30 + \ Add 30 to this
-
- D! \ Store screen pointer into NewWindow structure
-
- LIT$ $Tutorial Wind ow$ \ Title bar text for window
-
- 0 12 640 238 \ Guess what....Window dimensions!
- 3 \ 3 BitPlanes
- 0 \ No SUPERBITMAP
- OPENWINDOW \ Open the new window
-
- WINDOW D! \ and store window pointer/handle
-
- WINDOW D@ \ Check if opened OK, like screen above
-
- D0> \ See "screen open" check above........
-
- IF
-
- WINDOW D@
- MAKEGFXWINDOW \ Enable graphics in this window
-
- WINDOW D@
- MAKEOUTWINDOW \ Enable text output to this window
-
- WINDOW D@
- MAKEINWINDOW \ Enable user input from this window
-
- WINDOW D@ \ Get Window pointer
-
- 50. D+ \ Add 50 to Window Pointer to get RastPort
-
- D@L \ Get RASTPORT pointer
-
- RASTPORT D! \ Get Window's RastPort, and store it in
- \ variable RASTPORT
-
- RASTPORT D@
- 4. D+ D@L
- BITMAP D! \ Get the bitmap from the stored RastPort
-
- INTUBASE \ Put on the stack the 16-bit address
- \ where the 32-bit pointer to Intuition
- \ library base is stored
-
- -294 \ Put on the stack the offset of the library
- \ call "ViewAddress"
-
- LIBRARY \ Call Intuition Library function to get
- \ VIEW pointer
-
- D0RESULT \ Get dummy register D0 value which is the
- \ View address returned from the library call
-
- VIEW D! \ Store pointer in variable VIEW
-
- 1 \ Put value "1" on stack to indicate that
- \ everything opened OK
- ELSE
- 0 \ Put "0" on stack to indicate failure
- THEN
- ELSE
- 0 \ Put "0" on stack to indicate failure
- THEN
- ; \ End of Colon Definition
-
-
- \ In a similar manner we have a defined a HeliOS word for the related
- \ close down routine.
-
-
- : CLOSESYSTEM \ Start the colon definition
-
- FORTHINWINDOW \ Redirect the input and output from
- FORTHOUTWINDOW \ program's window back to the HeliOS
- FWINDOW MAKEGFXWINDOW \ interactive environment
-
- WINDOW D@ \ Get contents of window handle store
- DFLAG \ Check and if Non-Zero put 1 on stack else
- \ put 0 on stack above window handle
-
- IF \ If window is open, ie handle is non zero
- CLOSEWINDOW \ Close it
- WINDOW D0! \ then set store to zero
- ELSE
- DDROP \ else cleanup stack (drop window handle)
- THEN \ end of If/Then structure
-
- SCREEN D@ \ Look at screen handle
- DFLAG \ Check and if Non-Zero put 1 on stack else
- \ put 0 on stack above screen handle
- IF \ If it is open......
- CLOSESCREEN
- SCREEN D0!
- ELSE
- DDROP
- THEN
-
- TIMEON \ Enable time display for the
- \ HeliOS screen before exiting
- ; \ End of colon definition
-
-
- \ Now we can use these functions in a small program:
-
-
- : TUTORIALPROGRAM
-
- OPENSYSTEM \ Open environment, returning 1 or 0
- \ indicating success or failure
-
- IF \ If 1 is returned, for "success"
-
- 1 GFXSETOPEN \ Set graphics outline pen colour to 1
-
- 1 GFXOUTLINE \ Switch on graphics OUTLINE mode
-
- 2 GFXSETAPEN \ Set graphics pen to "2" for circle
-
- 400 160 80 40 \ Circle coordinates
-
- GFXAREAELLIPSE \ Draw circle into off screen buffer
-
- GFXAREAEND \ Render circle to screen
-
- 0 GFXOUTLINE \ Switch off graphics OUTLINE mode
-
- 3 GFXSETAPEN \ Set graphics pen to "3" for text
-
- 100 200 GFXMOVE \ Set graphics pen position
-
- LIT$ $This is graphic text$ \ Text string
-
- COUNT \ Get text start and length
-
- GFXTEXT \ Output text
-
-
- 20 10 CURPUT \ Place cursor
-
- ." Hello....Press <SPACE> to exit!" \ Some console text output
-
-
- BEGIN \ Start a BEGIN/UNTIL construct
-
- KEY \ Wait for a keypress
-
- 32 \ ASCII code for <SPACE> is 32
-
- = \ See if KEY value = 32
-
- UNTIL \ Loop until result is TRUE
-
- THEN
-
- CLOSESYSTEM \ Close environment
- ;
-
- TUTORIALPROGRAM \ Actually execute the new "program" word.
-
- \ End of program
-
-
- *************************************************************************
-
- -------------------------------
- A few simple hints on debugging
- -------------------------------
-
- Debugging consists mainly of locating the area where a problem occurs.
-
- Doing this sometimes requires additional information about program
- execution, and in these cases the custom HeliOS debugger is very useful.
-
- Beware, however, of the common mistake of using a debugger to generate
- a lot of extra information which in fact confuses the issue and makes
- the task of debugging harder than it need be.
-
- Often the simple use of output statements within a program, along with
- careful inspection and analysis of the code, is all that is required.
-
- HeliOS has a very powerful user-configurable debugger, but for most
- debugging you should never need to use it! The following hints should
- be taken as general programming guidelines, and for detailed discussion
- of the HeliOS debugger you should refer to the debugger documentation.
-
- There are a few simple techniques which, combined with sensible programming
- strategies (for example, do not write 200k of source code altogether with
- no testing then expect it to work instantly...), will enable you to debug
- code very simply.
-
- When a bug occurs the program will often (probably!) crash.
-
- The best simple debugging technique is to put a repetitive debug line
- into the code up to and including the crash point.
-
- This line should display the stack status and wait for the space bar
- to be pressed. Something like the following will do nicely:
-
- ." Now at line xxx. Stack reads: " .S ." <SPACE> to continue" WAITSPACE CR
-
-
- A few of these lines included in your code will give you a sequential
- talk-through until the crash point is reached.
-
- Start with the high level code first and then work into your subroutines:
- in this way you can home in on the actual fault. It is good practice to
- check each subroutine thoroughly as it is completed, but nevertheless the
- most unexpected results can occur when even apparantly sound subroutines
- are used together in complex ways.
-
- The stack status message debug line suggested above will probably mess up
- your program's screen display, but that does not really matter in a debug
- operation.
-
- Always check for stack aberrations first: be aware of what the stack should
- be reading and check your debug stack readouts scrupulously.
-
- If you like, include DUMP commands in your debug instructions to dump areas
- of memory for careful scrutiny.
-
- There are so many ways for code to fail it is impossible to cover all the
- aspects of debugging: also debugging is a very intuitive thing and everyone
- has very personal preferences.
-
- The main thing is to never assume ANYTHING to be OK without double checking,
- and be prepared to be patient and check EVERYTHING relating to your problem
- with an open mind.
-
- Check your stack dumps minutely, dump and also check any areas of memory
- you think may be suspect, check variable values by including them in your
- debug lines where appropriate.
-
- One big source of trouble is using address pointers which should really be
- pointing at something useful like a screen structure address, but actually
- contain zero. For example, in our little program above, we checked that
- the screen had opened OK and that its returned value was not null. If we
- did not do this and then went on to use the screen handle, not realising
- that it was zero, terrible things would happen.....
-
- This sort of mistake is quite easy to make in more complex code.
-
- A golden rule on a multitasking machine like the Amiga is never to assume
- that an allocation or opening routine must always succeed.
-
- Always check to see if everything has opened correctly, and always take care
- to initialise all fields of data structures correctly.
-
- *************************************************************************
-
- -------------------
- Additional reading?
- -------------------
-
- Perhaps you are wondering whether HeliOS is similar to any other languages
- and whether you can get any books to help you learn to program?
-
- It is always useful to read a variety of documentary material when you are
- learning a new programming language because different authors will often
- give you very different and valuable insights.
-
- HeliOS is a threaded interpretive language derived from Forth, so many of
- its simplest commands are Forth oriented. A basic understanding of Forth
- (which is a much smaller language in scope than HeliOS) will certainly help
- you get started with HeliOS, and if you have access to any Forth textbooks
- these will give you a good idea of the way HeliOS programs are structured.
-
- Forth text books will provide you with many helpful insights if you want
- to read them as background information: however, you should beware of taking
- the analogy between Forth and HeliOS too far. The fact is that superficial
- similarity between the languages can be deceptive, so take care.....
-
- As a Forth instructional text we advise you to search out Leo Brodie's
- excellent text "Starting Forth", published by Prentice Hall in paperback.
- The same author and publisher also produce a book called Thinking Forth,
- which is well worth reading for its insights into clever Forth programming
- strategy.
-
- You will certainly need to study specialised texts on the Amiga if you
- want to get the best out of HeliOS because HeliOS, like "C", makes use of
- the Amiga operating system and also allows direct Amiga hardware control.
-
- The Addison-Wesley Amiga manuals are an excellent investment if you are
- serious about Amiga programming, and Compute Books' "Mapping the Amiga"
- is an extremely useful reference text.
-
- HeliOS can supply an excellent comprehensive set of example programs on
- all HeliOS commands written by Sebastien Veyrin-Forrer. These short
- example programs detail the use of every word in the HeliOS vocabulary.
-
- ----------------------------------------------------------------------
- End
- ----------------------------------------------------------------------
-